﻿namespace My.Hydrator.Configuration
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using My.Hydrator.Conventions;
    using My.Hydrator.Helpers;

    public class DictionaryExpression<TKeyType, TValueType>
    {
        private readonly ConfigurationExpression configurationExpression;

        public DictionaryExpression(ConfigurationExpression configurationExpression)
        {
            this.configurationExpression = configurationExpression;
        }

        protected Container Container
        {
            get { return SessionHelper.Container; }
        }

        public void Generate(int numberOfElementsToGenerate)
        {
            var convention = new DictionaryTypeConvention(typeof(TKeyType), typeof(TValueType), numberOfElementsToGenerate);
            var type = typeof(Dictionary<,>).MakeGenericType(new[] { typeof(TKeyType), typeof(TValueType) });

            var conventionToReplace = this.GetConvention(type);
            if (conventionToReplace != null)
            {
                this.Container.Conventions.Remove(conventionToReplace);
            }

            this.Container.Conventions.Add(convention);
        }

        public void Generate(int numberOfElementsToGenerate, ITypeConvention genericKeyParameterConvention, ITypeConvention genericValueParameterConvention)
        {
            if (genericKeyParameterConvention.Type != typeof(TKeyType) || genericValueParameterConvention.Type != typeof(TValueType))
            {
                throw new ArgumentException();
            }

            var convention = new DictionaryTypeConvention(genericKeyParameterConvention, genericValueParameterConvention, numberOfElementsToGenerate);
            var type = typeof(Dictionary<,>).MakeGenericType(new[] { typeof(TKeyType), typeof(TValueType) });

            var conventionToReplace = this.GetConvention(type);
            if (conventionToReplace != null)
            {
                this.Container.Conventions.Remove(conventionToReplace);
            }

            this.Container.Conventions.Add(convention);
        }

        public void Use(IDictionaryTypeConvention dictionaryTypeConvention)
        {
            if (dictionaryTypeConvention == null)
            {
                throw new ArgumentNullException();
            }

            var type = typeof(Dictionary<,>).MakeGenericType(new[] { typeof(TKeyType), typeof(TValueType) });

            var conventionToReplace = this.GetConvention(type);
            if (conventionToReplace != null)
            {
                this.Container.Conventions.Remove(conventionToReplace);
            }

            this.Container.Conventions.Add(dictionaryTypeConvention);
        }

        private ITypeConvention GetConvention(Type type)
        {
            return this.Container.Conventions.SingleOrDefault(x => x.Type == type);
        }
    }
}
